/*
 * $Id: BatchedPreparedStatement.java 384 2012-04-26 04:37:21Z tweea $
 * Copyright(C) 2009 matrix
 * All right reserved.
 */
package net.matrix.sql;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

/**
 * 可以批量执行的 PreparedStatement。
 */
public class BatchedPreparedStatement
	implements PreparedStatement {
	/**
	 * 被包装的 PreparedStatement。
	 */
	private PreparedStatement statement;

	/**
	 * 最大批量执行的语句数量。
	 */
	private int batchSize;

	/**
	 * 等待批量执行的语句数量。
	 */
	private int batchCount;

	/**
	 * 包装一个 PreparedStatement，不使用批量执行。
	 * 
	 * @param statement
	 *            被包装的 PreparedStatement
	 */
	public BatchedPreparedStatement(final PreparedStatement statement) {
		this(statement, 0);
	}

	/**
	 * 包装一个 PreparedStatement，指定最大批量执行数量。
	 * 
	 * @param statement
	 *            被包装的 PreparedStatement
	 * @param batchSize
	 *            最大批量执行数量
	 */
	public BatchedPreparedStatement(final PreparedStatement statement, final int batchSize) {
		this.statement = statement;
		this.batchSize = batchSize;
		this.batchCount = 0;
	}

	/**
	 * 检查等待批量执行的语句数量，如果已达到最大数量，则向数据库发送执行。
	 * 
	 * @throws SQLException
	 *             数据库执行出错
	 */
	private void checkBatchCount()
		throws SQLException {
		if (batchSize > 0 && batchCount >= batchSize) {
			batchCount = 0;
			statement.executeBatch();
		}
	}

	/**
	 * 等待批量执行的语句数量加一。
	 */
	private void addBatchCount() {
		if (batchSize > 0) {
			batchCount++;
		}
	}

	/**
	 * 等待批量执行的语句数量清零。
	 */
	private void resetBatchCount() {
		batchCount = 0;
	}

	@Override
	public void addBatch()
		throws SQLException {
		checkBatchCount();
		statement.addBatch();
		addBatchCount();
	}

	@Override
	public void addBatch(final String sql)
		throws SQLException {
		checkBatchCount();
		statement.addBatch(sql);
		addBatchCount();
	}

	@Override
	public void cancel()
		throws SQLException {
		statement.cancel();
	}

	@Override
	public void clearBatch()
		throws SQLException {
		statement.clearBatch();
		resetBatchCount();
	}

	@Override
	public void clearParameters()
		throws SQLException {
		statement.clearParameters();
	}

	@Override
	public void clearWarnings()
		throws SQLException {
		statement.clearWarnings();
	}

	@Override
	public void close()
		throws SQLException {
		statement.close();
		resetBatchCount();
	}

	@Override
	public boolean execute()
		throws SQLException {
		return statement.execute();
	}

	@Override
	public boolean execute(final String sql, final int autoGeneratedKeys)
		throws SQLException {
		return statement.execute(sql, autoGeneratedKeys);
	}

	@Override
	public boolean execute(final String sql, final int[] columnIndexes)
		throws SQLException {
		return statement.execute(sql, columnIndexes);
	}

	@Override
	public boolean execute(final String sql, final String[] columnNames)
		throws SQLException {
		return statement.execute(sql, columnNames);
	}

	@Override
	public boolean execute(final String sql)
		throws SQLException {
		return statement.execute(sql);
	}

	@Override
	public int[] executeBatch()
		throws SQLException {
		int[] result = statement.executeBatch();
		resetBatchCount();
		return result;
	}

	@Override
	public ResultSet executeQuery()
		throws SQLException {
		return statement.executeQuery();
	}

	@Override
	public ResultSet executeQuery(final String sql)
		throws SQLException {
		return statement.executeQuery(sql);
	}

	@Override
	public int executeUpdate()
		throws SQLException {
		return statement.executeUpdate();
	}

	@Override
	public int executeUpdate(final String sql, final int autoGeneratedKeys)
		throws SQLException {
		return statement.executeUpdate(sql, autoGeneratedKeys);
	}

	@Override
	public int executeUpdate(final String sql, final int[] columnIndexes)
		throws SQLException {
		return statement.executeUpdate(sql, columnIndexes);
	}

	@Override
	public int executeUpdate(final String sql, final String[] columnNames)
		throws SQLException {
		return statement.executeUpdate(sql, columnNames);
	}

	@Override
	public int executeUpdate(final String sql)
		throws SQLException {
		return statement.executeUpdate(sql);
	}

	@Override
	public Connection getConnection()
		throws SQLException {
		return statement.getConnection();
	}

	@Override
	public int getFetchDirection()
		throws SQLException {
		return statement.getFetchDirection();
	}

	@Override
	public int getFetchSize()
		throws SQLException {
		return statement.getFetchSize();
	}

	@Override
	public ResultSet getGeneratedKeys()
		throws SQLException {
		return statement.getGeneratedKeys();
	}

	@Override
	public int getMaxFieldSize()
		throws SQLException {
		return statement.getMaxFieldSize();
	}

	@Override
	public int getMaxRows()
		throws SQLException {
		return statement.getMaxRows();
	}

	@Override
	public ResultSetMetaData getMetaData()
		throws SQLException {
		return statement.getMetaData();
	}

	@Override
	public boolean getMoreResults()
		throws SQLException {
		return statement.getMoreResults();
	}

	@Override
	public boolean getMoreResults(final int current)
		throws SQLException {
		return statement.getMoreResults(current);
	}

	@Override
	public ParameterMetaData getParameterMetaData()
		throws SQLException {
		return statement.getParameterMetaData();
	}

	@Override
	public int getQueryTimeout()
		throws SQLException {
		return statement.getQueryTimeout();
	}

	@Override
	public ResultSet getResultSet()
		throws SQLException {
		return statement.getResultSet();
	}

	@Override
	public int getResultSetConcurrency()
		throws SQLException {
		return statement.getResultSetConcurrency();
	}

	@Override
	public int getResultSetHoldability()
		throws SQLException {
		return statement.getResultSetHoldability();
	}

	@Override
	public int getResultSetType()
		throws SQLException {
		return statement.getResultSetType();
	}

	@Override
	public int getUpdateCount()
		throws SQLException {
		return statement.getUpdateCount();
	}

	@Override
	public SQLWarning getWarnings()
		throws SQLException {
		return statement.getWarnings();
	}

	@Override
	public boolean isClosed()
		throws SQLException {
		return statement.isClosed();
	}

	@Override
	public boolean isPoolable()
		throws SQLException {
		return statement.isPoolable();
	}

	@Override
	public boolean isWrapperFor(final Class<?> iface)
		throws SQLException {
		return statement.isWrapperFor(iface);
	}

	@Override
	public void setArray(final int parameterIndex, final Array x)
		throws SQLException {
		statement.setArray(parameterIndex, x);
	}

	@Override
	public void setAsciiStream(final int parameterIndex, final InputStream x, final int length)
		throws SQLException {
		statement.setAsciiStream(parameterIndex, x, length);
	}

	@Override
	public void setAsciiStream(final int parameterIndex, final InputStream x, final long length)
		throws SQLException {
		statement.setAsciiStream(parameterIndex, x, length);
	}

	@Override
	public void setAsciiStream(final int parameterIndex, final InputStream x)
		throws SQLException {
		statement.setAsciiStream(parameterIndex, x);
	}

	@Override
	public void setBigDecimal(final int parameterIndex, final BigDecimal x)
		throws SQLException {
		statement.setBigDecimal(parameterIndex, x);
	}

	@Override
	public void setBinaryStream(final int parameterIndex, final InputStream x, final int length)
		throws SQLException {
		statement.setBinaryStream(parameterIndex, x, length);
	}

	@Override
	public void setBinaryStream(final int parameterIndex, final InputStream x, final long length)
		throws SQLException {
		statement.setBinaryStream(parameterIndex, x, length);
	}

	@Override
	public void setBinaryStream(final int parameterIndex, final InputStream x)
		throws SQLException {
		statement.setBinaryStream(parameterIndex, x);
	}

	@Override
	public void setBlob(final int parameterIndex, final Blob x)
		throws SQLException {
		statement.setBlob(parameterIndex, x);
	}

	@Override
	public void setBlob(int parameterIndex, InputStream inputStream, long length)
		throws SQLException {
		statement.setBlob(parameterIndex, inputStream, length);
	}

	@Override
	public void setBlob(int parameterIndex, InputStream inputStream)
		throws SQLException {
		statement.setBlob(parameterIndex, inputStream);
	}

	@Override
	public void setBoolean(int parameterIndex, boolean x)
		throws SQLException {
		statement.setBoolean(parameterIndex, x);
	}

	@Override
	public void setByte(int parameterIndex, byte x)
		throws SQLException {
		statement.setByte(parameterIndex, x);
	}

	@Override
	public void setBytes(int parameterIndex, byte[] x)
		throws SQLException {
		statement.setBytes(parameterIndex, x);
	}

	@Override
	public void setCharacterStream(int parameterIndex, Reader reader, int length)
		throws SQLException {
		statement.setCharacterStream(parameterIndex, reader, length);
	}

	@Override
	public void setCharacterStream(int parameterIndex, Reader reader, long length)
		throws SQLException {
		statement.setCharacterStream(parameterIndex, reader, length);
	}

	@Override
	public void setCharacterStream(int parameterIndex, Reader reader)
		throws SQLException {
		statement.setCharacterStream(parameterIndex, reader);
	}

	@Override
	public void setClob(int parameterIndex, Clob x)
		throws SQLException {
		statement.setClob(parameterIndex, x);
	}

	@Override
	public void setClob(int parameterIndex, Reader reader, long length)
		throws SQLException {
		statement.setClob(parameterIndex, reader, length);
	}

	@Override
	public void setClob(int parameterIndex, Reader reader)
		throws SQLException {
		statement.setClob(parameterIndex, reader);
	}

	@Override
	public void setCursorName(String name)
		throws SQLException {
		statement.setCursorName(name);
	}

	@Override
	public void setDate(int parameterIndex, Date x)
		throws SQLException {
		statement.setDate(parameterIndex, x);
	}

	@Override
	public void setDate(int parameterIndex, Date x, Calendar cal)
		throws SQLException {
		statement.setDate(parameterIndex, x, cal);
	}

	@Override
	public void setDouble(int parameterIndex, double x)
		throws SQLException {
		statement.setDouble(parameterIndex, x);
	}

	@Override
	public void setEscapeProcessing(boolean enable)
		throws SQLException {
		statement.setEscapeProcessing(enable);
	}

	@Override
	public void setFetchDirection(int direction)
		throws SQLException {
		statement.setFetchDirection(direction);
	}

	@Override
	public void setFetchSize(int rows)
		throws SQLException {
		statement.setFetchSize(rows);
	}

	@Override
	public void setFloat(int parameterIndex, float x)
		throws SQLException {
		statement.setFloat(parameterIndex, x);
	}

	@Override
	public void setInt(int parameterIndex, int x)
		throws SQLException {
		statement.setInt(parameterIndex, x);
	}

	@Override
	public void setLong(int parameterIndex, long x)
		throws SQLException {
		statement.setLong(parameterIndex, x);
	}

	@Override
	public void setMaxFieldSize(int max)
		throws SQLException {
		statement.setMaxFieldSize(max);
	}

	@Override
	public void setMaxRows(int max)
		throws SQLException {
		statement.setMaxRows(max);
	}

	@Override
	public void setNCharacterStream(final int parameterIndex, final Reader value, final long length)
		throws SQLException {
		statement.setNCharacterStream(parameterIndex, value, length);
	}

	@Override
	public void setNCharacterStream(final int parameterIndex, final Reader value)
		throws SQLException {
		statement.setNCharacterStream(parameterIndex, value);
	}

	@Override
	public void setNClob(final int parameterIndex, final NClob value)
		throws SQLException {
		statement.setNClob(parameterIndex, value);
	}

	@Override
	public void setNClob(final int parameterIndex, final Reader reader, final long length)
		throws SQLException {
		statement.setNClob(parameterIndex, reader, length);
	}

	@Override
	public void setNClob(final int parameterIndex, final Reader reader)
		throws SQLException {
		statement.setNClob(parameterIndex, reader);
	}

	@Override
	public void setNString(final int parameterIndex, final String value)
		throws SQLException {
		statement.setNString(parameterIndex, value);
	}

	@Override
	public void setNull(final int parameterIndex, final int sqlType)
		throws SQLException {
		statement.setNull(parameterIndex, sqlType);
	}

	@Override
	public void setNull(final int parameterIndex, final int sqlType, final String typeName)
		throws SQLException {
		statement.setNull(parameterIndex, sqlType, typeName);
	}

	@Override
	public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scaleOrLength)
		throws SQLException {
		statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength);
	}

	@Override
	public void setObject(final int parameterIndex, final Object x, final int targetSqlType)
		throws SQLException {
		statement.setObject(parameterIndex, x, targetSqlType);
	}

	@Override
	public void setObject(final int parameterIndex, final Object x)
		throws SQLException {
		statement.setObject(parameterIndex, x);
	}

	@Override
	public void setPoolable(final boolean poolable)
		throws SQLException {
		statement.setPoolable(poolable);
	}

	@Override
	public void setQueryTimeout(final int seconds)
		throws SQLException {
		statement.setQueryTimeout(seconds);
	}

	@Override
	public void setRef(final int parameterIndex, final Ref x)
		throws SQLException {
		statement.setRef(parameterIndex, x);
	}

	@Override
	public void setRowId(final int parameterIndex, final RowId x)
		throws SQLException {
		statement.setRowId(parameterIndex, x);
	}

	@Override
	public void setShort(final int parameterIndex, final short x)
		throws SQLException {
		statement.setShort(parameterIndex, x);
	}

	@Override
	public void setSQLXML(final int parameterIndex, final SQLXML xmlObject)
		throws SQLException {
		statement.setSQLXML(parameterIndex, xmlObject);
	}

	@Override
	public void setString(final int parameterIndex, final String x)
		throws SQLException {
		statement.setString(parameterIndex, x);
	}

	@Override
	public void setTime(final int parameterIndex, final Time x)
		throws SQLException {
		statement.setTime(parameterIndex, x);
	}

	@Override
	public void setTime(final int parameterIndex, final Time x, final Calendar cal)
		throws SQLException {
		statement.setTime(parameterIndex, x, cal);
	}

	@Override
	public void setTimestamp(final int parameterIndex, final Timestamp x)
		throws SQLException {
		statement.setTimestamp(parameterIndex, x);
	}

	@Override
	public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal)
		throws SQLException {
		statement.setTimestamp(parameterIndex, x, cal);
	}

	@Deprecated
	@Override
	public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length)
		throws SQLException {
		statement.setUnicodeStream(parameterIndex, x, length);
	}

	@Override
	public void setURL(final int parameterIndex, final URL x)
		throws SQLException {
		statement.setURL(parameterIndex, x);
	}

	@Override
	public <T> T unwrap(final Class<T> iface)
		throws SQLException {
		return statement.unwrap(iface);
	}
}
